package com.uduemc.biso.node.web.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import com.uduemc.biso.core.extities.pojo.DeployType;
import com.uduemc.biso.core.utils.FileZip;
import com.uduemc.biso.node.core.common.utils.AssetsUtil;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.web.component.DeployFunction;
import com.uduemc.biso.node.web.component.LinuxCommond;
import com.uduemc.biso.node.web.service.DeployService;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class DeployServiceImpl implements DeployService {

	@Autowired
	GlobalProperties globalProperties;

	@Autowired
	DeployFunction deployFunction;

	@Autowired
	LinuxCommond linuxCommond;

	@Override
	public Map<String, String> versionInfos() {
		Map<String, String> result = new HashMap<>();
		DeployFunction.deploies.forEach(item -> {
			try {
				result.put(item, deployFunction.localhostVersion(item));
			} catch (IOException e) {
				e.printStackTrace();
			}
		});
		return result;
	}

	@Override
	public String localhostVersion(String deployname) throws IOException {
		String localhostVersion = deployFunction.localhostVersion(deployname);
		return StringUtils.isBlank(localhostVersion) ? "" : localhostVersion;
	}

	@Override
	public boolean theLast(String deployname) throws IOException {
		String lastVersion = deployFunction.lastVersion(deployname);
		String localhostVersion = localhostVersion(deployname);

		return StringUtils.isBlank(localhostVersion) || StringUtils.isBlank(lastVersion) ? false
				: localhostVersion.equals(lastVersion);
	}

	@Override
	public boolean deploy(String deployname) throws IOException {
		if (deployname.equals(DeployType.NODE_BACKEND)) {
			return deployNodeBackend();
		} else if (deployname.equals(DeployType.COMPONENTS)) {
			return deployComponents();
		} else if (deployname.equals(DeployType.BACKENDJS)) {
			return deployBackendjs();
		} else if (deployname.equals(DeployType.SITEJS)) {
			return deploySitejs();
		} else {
			log.error("未定义的 DeployType ：" + deployname);
		}
		return false;
	}

	@Override
	public boolean deploy(String deployname, String version) throws IOException {
		if (deployname.equals(DeployType.NODE_BACKEND)) {
			return deployNodeBackend(version);
		} else if (deployname.equals(DeployType.COMPONENTS)) {
			return deployComponents(version);
		} else if (deployname.equals(DeployType.BACKENDJS)) {
			return deployBackendjs(version);
		} else if (deployname.equals(DeployType.SITEJS)) {
			return deploySitejs(version);
		} else {
			log.error("未定义的 DeployType ：" + deployname);
		}
		return false;
	}

	@Override
	public boolean deployNodeBackend() throws IOException {
		boolean theLast = theLast(DeployType.NODE_BACKEND);
		if (theLast) {
			return true;
		}
		// 执行升级步骤
		String version = deployFunction.lastNodeBackendVersion();
		if (StringUtils.isBlank(version)) {
			log.error("获取 " + DeployType.NODE_BACKEND + " 的最新 version 失败！");
			return false;
		}

		boolean deployNodeBackend = deployNodeBackend(version);
		if (!deployNodeBackend) {
			return false;
		}
		return theLast(DeployType.NODE_BACKEND);
	}

	@Override
	public boolean deployComponents() throws IOException {
		boolean theLast = theLast(DeployType.COMPONENTS);
		if (theLast) {
			return true;
		}
		// 执行升级步骤
		String version = deployFunction.lastComponentsVersion();
		boolean deployComponents = deployComponents(version);
		if (!deployComponents) {
			return false;
		}
		return theLast(DeployType.COMPONENTS);
	}

	@Override
	public boolean deployBackendjs() throws IOException {
		boolean theLast = theLast(DeployType.BACKENDJS);
		if (theLast) {
			return true;
		}
		// 执行升级步骤
		String version = deployFunction.lastBackendjsVersion();
		boolean deployBackendjs = deployBackendjs(version);
		if (!deployBackendjs) {
			return false;
		}
		return theLast(DeployType.BACKENDJS);
	}

	@Override
	public boolean deploySitejs() throws IOException {
		boolean theLast = theLast(DeployType.SITEJS);
		if (theLast) {
			return true;
		}
		// 执行升级步骤
		String version = deployFunction.lastSitejsVersion();
		boolean deploySitejs = deploySitejs(version);
		if (!deploySitejs) {
			return false;
		}
		return theLast(DeployType.SITEJS);
	}

	protected static String regMetaMatch(String withinText) {
		String code = null;
		Pattern pattern = Pattern.compile("<meta name=\"?deploy-name\"? content=\"?(.*?)\"?\\s?/?>");
		Matcher matcher = pattern.matcher(withinText);
		if (matcher.find()) {
			matcher.reset();
			while (matcher.find()) {
				return matcher.group(1);
			}
		}
		return code;
	}

	@Override
	public boolean deployNodeBackend(String version) throws IOException {
		// 执行升级步骤
		if (StringUtils.isBlank(version)) {
			log.error("获取 " + DeployType.NODE_BACKEND + " 的最新 version 失败！");
			return false;
		}
		String zipPath = deployFunction.downloadAndZipPathNodeBackend(version);
		if (StringUtils.isBlank(zipPath) || !new File(zipPath).isFile()) {
			return false;
		}
		String nodeBackendTmp = globalProperties.getNode().getNodeBackendPath() + "_zip_tmp";

		File nodeBackendTmpFile = new File(nodeBackendTmp);
		if (nodeBackendTmpFile.isDirectory()) {
			FileUtils.deleteDirectory(nodeBackendTmpFile);
		}

		FileZip.decompress(zipPath, nodeBackendTmp);

		// 验证 newDist 中index.html验证码是否正确
		File newDist = new File(nodeBackendTmp + File.separator + "node-backend_dist");
		File index = FileUtils.getFile(newDist, "index.html");
		String html = FileUtils.readFileToString(index, "UTF-8");
		String code = regMetaMatch(html);
		String md5DigestAsHex = DigestUtils.md5DigestAsHex(DeployType.NODE_BACKEND.getBytes());
		if (StringUtils.isBlank(code) || !code.toLowerCase().equals(md5DigestAsHex.toLowerCase())) {
			log.error("部署升级 " + DeployType.NODE_BACKEND + " 失败，下载的压缩文件无法获取到工程验证码或者获取的工程验证码不匹配！ 正确的验证码："
					+ md5DigestAsHex.toLowerCase());
			FileUtils.deleteDirectory(nodeBackendTmpFile);
			return false;
		}

		File nodeBackendFile = new File(globalProperties.getNode().getNodeBackendPath());
		File nodeBackendOldFile = new File(globalProperties.getNode().getNodeBackendPath() + "_old_tmp");
		if (nodeBackendFile.isDirectory()) {
			if (nodeBackendOldFile.isDirectory()) {
				FileUtils.deleteDirectory(nodeBackendOldFile);
			}
			FileUtils.copyDirectory(nodeBackendFile, nodeBackendOldFile);
		}

		// 复制到项目的目录
		FileUtils.copyDirectory(newDist, nodeBackendFile);
		linuxCommond.chmodDir(nodeBackendFile.getPath(), "755", true);
		if (nodeBackendTmpFile.isDirectory()) {
			FileUtils.deleteDirectory(nodeBackendTmpFile);
		}
		if (nodeBackendOldFile.isDirectory()) {
			FileUtils.deleteDirectory(nodeBackendOldFile);
		}

		// 写入当前的版本号
		deployFunction.localhostNodeBackendVersionWrite(version);
		return version.equals(localhostVersion(DeployType.NODE_BACKEND));
	}

	@Override
	public boolean deployComponents(String version) throws IOException {
		// 执行升级步骤
		if (StringUtils.isBlank(version)) {
			log.error("获取 " + DeployType.COMPONENTS + " 的最新 version 失败！");
			return false;
		}
		String zipPath = deployFunction.downloadAndZipPathComponents(version);
		if (StringUtils.isBlank(zipPath) || !new File(zipPath).isFile()) {
			return false;
		}
		String componentsTmp = AssetsUtil.getComponentsDistPath(globalProperties.getSite().getAssetsPath())
				+ "_zip_tmp";
		File componentsTmpFile = new File(componentsTmp);
		if (componentsTmpFile.isDirectory()) {
			FileUtils.deleteDirectory(componentsTmpFile);
		}

		FileZip.decompress(zipPath, componentsTmp);

		// 验证 newDist 中index.html验证码是否正确
		File newDist = new File(componentsTmp + File.separator + "components_dist");
		File index = FileUtils.getFile(newDist, "index.html");
		String html = FileUtils.readFileToString(index, "UTF-8");
		String code = regMetaMatch(html);
		String md5DigestAsHex = DigestUtils.md5DigestAsHex(DeployType.COMPONENTS.getBytes());
		if (StringUtils.isBlank(code) || !code.toLowerCase().equals(md5DigestAsHex.toLowerCase())) {
			log.error("部署升级 " + DeployType.COMPONENTS + " 失败，下载的压缩文件无法获取到工程验证码或者获取的工程验证码不匹配！ 正确的验证码："
					+ md5DigestAsHex.toLowerCase());
			FileUtils.deleteDirectory(componentsTmpFile);
			return false;
		}

		File componentsFile = new File(AssetsUtil.getComponentsDistPath(globalProperties.getSite().getAssetsPath()));
		File componentsOldFile = new File(
				AssetsUtil.getComponentsDistPath(globalProperties.getSite().getAssetsPath()) + "_old_tmp");
		if (componentsFile.isDirectory()) {
			if (componentsOldFile.isDirectory()) {
				FileUtils.deleteDirectory(componentsOldFile);
			}
			FileUtils.copyDirectory(componentsFile, componentsOldFile);
		}

		// 复制到项目的目录
		FileUtils.copyDirectory(newDist, componentsFile);
		linuxCommond.chmodDir(componentsFile.getPath(), "755", true);

		if (componentsTmpFile.isDirectory()) {
			FileUtils.deleteDirectory(componentsTmpFile);
		}
		if (componentsOldFile.isDirectory()) {
			FileUtils.deleteDirectory(componentsOldFile);
		}

		// 写入当前的版本号
		deployFunction.localhostComponentsVersionWrite(version);
		return version.equals(localhostVersion(DeployType.COMPONENTS));
	}

	@Override
	public boolean deployBackendjs(String version) throws IOException {
		// 执行升级步骤
		if (StringUtils.isBlank(version)) {
			log.error("获取 " + DeployType.BACKENDJS + " 的最新 version 失败！");
			return false;
		}
		String zipPath = deployFunction.downloadAndZipPathBackendjs(version);
		if (StringUtils.isBlank(zipPath) || !new File(zipPath).isFile()) {
			return false;
		}
		String backendjsTmp = AssetsUtil.getBackendjsRootPath(globalProperties.getSite().getAssetsPath()) + "_zip_tmp";

		File backendjsTmpFile = new File(backendjsTmp);
		if (backendjsTmpFile.isDirectory()) {
			FileUtils.deleteDirectory(backendjsTmpFile);
		}

		FileZip.decompress(zipPath, backendjsTmp);

		// 验证 newDist 中index.html验证码是否正确
		File newDist = new File(backendjsTmp + File.separator + "backendjs_dist");
		File index = FileUtils.getFile(newDist, "index.html");
		String html = FileUtils.readFileToString(index, "UTF-8");
		String code = regMetaMatch(html);
		String md5DigestAsHex = DigestUtils.md5DigestAsHex(DeployType.BACKENDJS.getBytes());
		if (StringUtils.isBlank(code) || !code.toLowerCase().equals(md5DigestAsHex.toLowerCase())) {
			log.error("部署升级 " + DeployType.BACKENDJS + " 失败，下载的压缩文件无法获取到工程验证码或者获取的工程验证码不匹配！ 正确的验证码："
					+ md5DigestAsHex.toLowerCase());
			FileUtils.deleteDirectory(backendjsTmpFile);
			return false;
		}

		File backendjsFile = new File(AssetsUtil.getBackendjsRootPath(globalProperties.getSite().getAssetsPath()));
		File backendjsOldFile = new File(
				AssetsUtil.getBackendjsRootPath(globalProperties.getSite().getAssetsPath()) + "_old_tmp");
		if (backendjsFile.isDirectory()) {
			if (backendjsOldFile.isDirectory()) {
				FileUtils.deleteDirectory(backendjsOldFile);
			}
			FileUtils.copyDirectory(backendjsFile, backendjsOldFile);
		}

		// 复制到项目的目录
		FileUtils.copyDirectory(newDist, backendjsFile);
		linuxCommond.chmodDir(backendjsFile.getPath(), "755", true);

		if (backendjsTmpFile.isDirectory()) {
			FileUtils.deleteDirectory(backendjsTmpFile);
		}

		if (backendjsOldFile.isDirectory()) {
			FileUtils.deleteDirectory(backendjsOldFile);
		}

		// 写入当前的版本号
		deployFunction.localhostBackendjsVersionWrite(version);
		return version.equals(localhostVersion(DeployType.BACKENDJS));
	}

	@Override
	public boolean deploySitejs(String version) throws IOException {
		// 执行升级步骤
		if (StringUtils.isBlank(version)) {
			log.error("获取 " + DeployType.SITEJS + " 的最新 version 失败！");
			return false;
		}
		String zipPath = deployFunction.downloadAndZipPathSitejs(version);
		if (StringUtils.isBlank(zipPath) || !new File(zipPath).isFile()) {
			return false;
		}
		String sitejsTmp = AssetsUtil.getSitejsRootPath(globalProperties.getSite().getAssetsPath()) + "_zip_tmp";

		File sitejsTmpFile = new File(sitejsTmp);
		if (sitejsTmpFile.isDirectory()) {
			FileUtils.deleteDirectory(sitejsTmpFile);
		}

		FileZip.decompress(zipPath, sitejsTmp);

		// 验证 newDist 中index.html验证码是否正确
		File newDist = new File(sitejsTmp + File.separator + "sitejs_dist");
		File index = FileUtils.getFile(newDist, "index.html");
		String html = FileUtils.readFileToString(index, "UTF-8");
		String code = regMetaMatch(html);
		String md5DigestAsHex = DigestUtils.md5DigestAsHex(DeployType.SITEJS.getBytes());
		if (StringUtils.isBlank(code) || !code.toLowerCase().equals(md5DigestAsHex.toLowerCase())) {
			log.error("部署升级 " + DeployType.SITEJS + " 失败，下载的压缩文件无法获取到工程验证码或者获取的工程验证码不匹配！ 正确的验证码："
					+ md5DigestAsHex.toLowerCase());
			FileUtils.deleteDirectory(sitejsTmpFile);
			return false;
		}

		File sitejsFile = new File(AssetsUtil.getSitejsRootPath(globalProperties.getSite().getAssetsPath()));
		File sitejsOldFile = new File(
				AssetsUtil.getSitejsRootPath(globalProperties.getSite().getAssetsPath()) + "_old_tmp");
		if (sitejsFile.isDirectory()) {
			if (sitejsOldFile.isDirectory()) {
				FileUtils.deleteDirectory(sitejsOldFile);
			}
			FileUtils.copyDirectory(sitejsFile, sitejsOldFile);
		}

		// 复制到项目的目录
		FileUtils.copyDirectory(newDist, sitejsFile);
		linuxCommond.chmodDir(sitejsFile.getPath(), "755", true);

		if (sitejsTmpFile.isDirectory()) {
			FileUtils.deleteDirectory(sitejsTmpFile);
		}

		if (sitejsOldFile.isDirectory()) {
			FileUtils.deleteDirectory(sitejsOldFile);
		}

		// 写入当前的版本号
		deployFunction.localhostSitejsVersionWrite(version);
		return version.equals(localhostVersion(DeployType.SITEJS));
	}

}
